/**
 * @author Luc Yriarte
 * 
 * Licence : BSD http://www.opensource.org/licenses/bsd-license.php
 *  
 */
package objectEditor;

import java.applet.Applet;
import java.awt.Button;
import java.awt.Checkbox;
import java.awt.Choice;
import java.awt.Event;
import java.awt.Graphics;
import java.awt.TextArea;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;

import basicSim.Animation;
import basicSim.BackBufferedGraphics;
import basicSim.Matrix3D;
import basicSim.Object3D;
import basicSim.Object3DFactory;
import basicSim.PolySphere;

public class ObjectEditorApplet extends Applet implements ActionListener,
		ItemListener {

	static int NAV_ROTATION = 0, NAV_TRANSLATION = 1, NAV_ZOOM = 2;
	static int DEFAULT_FOCAL = 200, DEFAULT_Z = 200, DEFAULT_MS = 83; // 12 fps

	int width, height;
	
	Checkbox drawFacets;
	Checkbox showText;
	Choice navMenu;
	TextArea codeField;
	Button readButton;

	Object3D model;
	Animation anime;
//	SimView bbG;
	BackBufferedGraphics bbG;
	int ms, focal, dragX, dragY;

	public ObjectEditorApplet() {
		super();
		anime = null;
		
		drawFacets = new Checkbox("Facets", true);
		drawFacets.addItemListener(this);

		navMenu = new Choice();
		navMenu.addItemListener(this);
		navMenu.addItem("Rotate");
		navMenu.addItem("Translate");
		navMenu.addItem("Zoom");

		showText = new Checkbox("Show text");
		showText.addItemListener(this);
	}

	public void showTextControls() {
		readButton = new Button("Create model");
		add(readButton);
		readButton.addActionListener(this);
		codeField = new TextArea(5, 30);
		add(codeField);
		codeField.setText(model.toString());
		validate();
	}

	public void hideTextControls() {
		remove(readButton);
		remove(codeField);
		readButton = null;
		codeField = null;
		validate();
	}

	public void init() {
		width = this.getSize().width;
		height = this.getSize().height;
		String str;
		double z;
		
		str = getParameter("N");
		if (str != null)
			Object3D.N_DEFAULT = new Integer(str).intValue();
			
		str = getParameter("Z");
		z = (str == null) ? DEFAULT_Z : new Double(str).doubleValue();
			
		str = getParameter("Focal");
		focal = (str == null) ? DEFAULT_FOCAL : new Integer(str).intValue();
			
		str = getParameter("ms");
		ms = (str == null) ? DEFAULT_MS : new Integer(str).intValue();
			
		str = getParameter("Model");
		model = (str == null) ? new PolySphere(100) : Object3DFactory.NewObject3D(str);

		str = getParameter("Edit");
		if (str != null && str.equals("true")) add(showText);
		
		str = getParameter("Nav");
		if (str == null)
			add(navMenu);
		else if (str.equals("Rotate"))
			navMenu.select(NAV_ROTATION);
		else if (str.equals("Translate"))
			navMenu.select(NAV_TRANSLATION);
		else if (str.equals("Zoom"))
			navMenu.select(NAV_ZOOM);
		
		str = getParameter("Facets");
		if (str == null)
			add(drawFacets);
		else if (str.equals("false"))
			drawFacets.setState(false);
		
//		bbG = new SimView(model, this.getGraphics(), width, height, focal);
		bbG = new BackBufferedGraphics(model, this.createImage(width,height), width, height, focal);
		bbG.drawFacets = drawFacets.getState();
		
		model.setPosition(Matrix3D.translation(0, 0, z));
		
		// ---- ---- update and paint
		bbG.updateModel();
		repaint();
		
		// ---- ---- parsed animation ?
		if (Object3DFactory.getAnimation() != null) {
			anime = Object3DFactory.getAnimation();
			Object3DFactory.resetAnimation();
			anime.view = this;
			anime.objView = bbG;
			anime.millisec = ms;
			anime.start();
		}		
	}
	
	public void paint(Graphics g) {
		bbG.updateGraphics(g);
	}

	public void update(Graphics g) {
		this.paint(g);
	}

	public boolean mouseDown(Event arg0, int arg1, int arg2) {
		dragX = arg1;
		dragY = arg2;
		return true;
	}

	public boolean mouseDrag(Event arg0, int arg1, int arg2) {
		double deltaX, deltaY, deltaZ;
		if (navMenu.getSelectedIndex() == NAV_ROTATION) {
			deltaX = (arg1 - dragX) * 2 * Math.PI / width;
			deltaY = (dragY - arg2) * 2 * Math.PI / height;
			model
					.setOrientation(model.getOrientation().mul(
							Matrix3D.rotationY(deltaX).mul(
									Matrix3D.rotationX(deltaY))));
		} else if (navMenu.getSelectedIndex() == NAV_TRANSLATION) {
			deltaX = (arg1 - dragX);
			deltaY = (dragY - arg2);
			model.setPosition(model.getPosition().mul(
					Matrix3D.translation(deltaX, deltaY, 0)));
		} else if (navMenu.getSelectedIndex() == NAV_ZOOM) {
			deltaZ = arg2 - dragY;
			model.setPosition(model.getPosition().mul(
					Matrix3D.translation(0, 0, deltaZ)));
		}
		bbG.updateModel();
		repaint();
		dragX = arg1;
		dragY = arg2;
		return true;
	}

	public boolean mouseUp(Event arg0, int arg1, int arg2) {
		dragX = dragY = 0;
		return true;
	}

	public void itemStateChanged(ItemEvent arg0) {
		if (arg0.getSource() == showText) {
			if (showText.getState())
				showTextControls();
			else
				hideTextControls();
		} else if (arg0.getSource() == drawFacets) {
			bbG.drawFacets = drawFacets.getState();
			bbG.updateModel();
			repaint();
		}
	}

	public void actionPerformed(ActionEvent arg0) {
		Object src = arg0.getSource();
		if (src == readButton) {
			if (anime != null) {
				anime.nObjects = 0;
				anime = null;
			}
			model = Object3DFactory.NewObject3D(codeField.getText());
//System.out.println(model.toString());
			bbG.model = model;
			model.setPosition(Matrix3D.translation(0, 0, DEFAULT_Z));
			bbG.updateModel();
			repaint();
			if (Object3DFactory.getAnimation() != null) {
				anime = Object3DFactory.getAnimation();
				Object3DFactory.resetAnimation();
				anime.view = this;
				anime.objView = bbG;
				anime.millisec = ms;
				anime.start();
			}
		}
	}

}
